// 闭包是指有权访问另一个函数作用域中变量的函数
// 创建闭包最常见的方式就是，在一个函数内部创建另一个函数
// 闭包通常用来创建内部变量，使得 这些变量不能被外部随意修改，同时又可以通过指定的接口来操作

// eg1 
function foo() {
    var a = 1;  // a是一个被foo创建的局部变量

    function bar() {   // bar是一个内部函数，是一个闭包
        // var b = 2;
        console.log(a);  // 使用了父函数中声明的变量
    };

    // console.log(b);   // ReferenceError: b is not defined
    return bar();
};

foo();  // 1

// 在eg1中foo()函数中声明了一个内部变量a，在函数外是无法访问的
// bar()函数是foo()函数内部的函数，此时foo()内部的所有局部变量，bar()都可以访问，反之不行

// eg2
function foo() {
    var a = 1;  // a是一个被foo创建的局部变量

    function bar() {   // bar是一个内部函数，是一个闭包
        console.log(a);  // 使用了父函数中声明的变量
    };

    return bar;
};

const myFoo = foo();
myFoo();

// foo()执行后，将其返回值bar函数赋值给myFoo，然后再调用myFoo()，实际上是通过不同的标识符引用调用了内部的函数bar()
// foo() 函数执行后，正常情况下 foo() 的整个内部作用域被销毁，占用的内存被回收
// 但是现在的 foo的内部作用域 bar() 还在使用，所以不会对其进行回收
// bar() 依然持有对改作用域的引用，这个引用就叫做闭包。这个函数在定义的词法作用域以外的地方被调用
// 闭包使得函数可以继续访问定义时的词法作用域（bar的词法作用域是foo函数内部）


// 因此，闭包容易造成内存泄漏

/*
    闭包怎么解决回收问题？

*/ 



// 词法作用域（Lexical Scope）
/*
    词法作用域是定义表达式并能被访问的区间
    一个声明（定义变量、函数等）的词法作用域就是他被定义时所在的作用域
    【切记 词法作用域 意味着 定义时的作用域，并不是调用时的作用域】
*/
